﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TA.DotNetUtils
{
	public class TemplateParser
	{
		#region PUBLIC
		#region EVENTS
		public event ResolvePlaceholderEventHandler ResolvePlaceholder;
		#endregion
		#region METHODS
		public string Parse(string template)
		{
			return this.DoParse(template);
		}
		public void AddObject(object obj, string prefix)
		{
			if (prefix == null) prefix = "";
			if (!this._objects.ContainsKey(prefix))
			{
				this._objects[prefix] = new List<object>();
			}
			this._objects[prefix].Add(obj);
		}
		#endregion
		#endregion
		#region INTERNAL
		#region CONST/STATIC
		const string PlaceHolderStartMarker = "##",
			PlaceHolderEndMarker = "##";
		#endregion
		#region VARS
		Dictionary<string, List<object>> _objects = new Dictionary<string, List<object>>();
		#endregion
		#region METHODS
		protected virtual string Resolve(string placeHolder)
		{
			string res = null;

			int dotPos = placeHolder.IndexOf(".");
			if (dotPos != -1)
			{
				string firstPart = placeHolder.Substring(0, dotPos);
				if (this._objects.ContainsKey(firstPart))
				{
					res = this.TryEvalPlaceholder(this._objects[firstPart], placeHolder.Substring(dotPos + 1));
				}
			}

			if (res == null)
			{
				if(this._objects.ContainsKey(""))
				{
					res = this.TryEvalPlaceholder(this._objects[""], placeHolder);
				}
			}

			ResolvePlaceholderEventArgs e = new ResolvePlaceholderEventArgs(placeHolder);
			e.Result = res;
			this.OnResolvePlaceholder(e);
			return e.Result;
		}

		private string TryEvalPlaceholder(List<object> list, string placeholder)
		{
			foreach (object obj in list)
			{
				try
				{
					object v = obj.Eval(placeholder);
					if (v != null) return v.ToString();
					return null;
				}
				catch
				{
				}
			}
			return null;
		}
		protected string DoParse(string template)
		{
			StringBuilder sbRes = new StringBuilder();
			string placeHolder;
			int startPos, endPos, lastPos = 0;
			for (int i = 0; i < template.Length; )
			{
				i = template.IndexOf(PlaceHolderStartMarker, lastPos);
				if (i == -1) break;
				startPos = i + PlaceHolderStartMarker.Length;
				endPos = template.IndexOf(PlaceHolderEndMarker, startPos);
				if (endPos == -1) break;
				placeHolder = template.Substring(startPos, endPos - startPos);

				sbRes.Append(template.Substring(lastPos, i - lastPos));

				sbRes.Append(this.Resolve(placeHolder));

				lastPos = endPos + PlaceHolderEndMarker.Length;
			}
			sbRes.Append(template.Substring(lastPos, template.Length - lastPos));
			return sbRes.ToString();
		}
		#region EVENTS
		protected virtual void OnResolvePlaceholder(ResolvePlaceholderEventArgs e)
		{
			if (this.ResolvePlaceholder != null)
				this.ResolvePlaceholder(this, e);
		}
		#endregion
		#endregion
		#endregion
	}
	public class ResolvePlaceholderEventArgs : EventArgs
	{
		#region PUBLIC
		#region INIT
		public ResolvePlaceholderEventArgs(string placeholder)
		{
			this._placeholder = placeholder;
		}
		#endregion
		#region EVENTS
		#endregion
		#region PROPS
		public string Placeholder
		{
			get
			{
				return this._placeholder;
			}
		}
		public string Result { get; set; }
		#endregion
		#region METHODS
		#endregion
		#endregion
		#region INTERNAL
		#region CONST/STATIC
		#endregion
		#region VARS
		string _placeholder;
		#endregion
		#region PROPS
		#endregion
		#region METHODS
		#region INIT
		#endregion
		#region DATA
		#endregion
		#region HANDLERS
		#endregion
		#endregion
		#endregion

	}
	public delegate void ResolvePlaceholderEventHandler(object sender, ResolvePlaceholderEventArgs e);
}
